package org.atlantis.grosbeak.plugin;

import java.util.ArrayList;
import java.util.List;

import org.atlantis.grosbeak.lang.Exceptions;

/**
 * 基本的插件加载引擎。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 * @param <T>
 */
public class BasePluginEngine<T> implements PluginEngine<T> {

	private List<Plugin> list = new ArrayList<Plugin>();

	/**
	 * 所需要加载的所有插件的全名（如：org.atlantis.grosbeak.plugin.demo.JsonPlugin）。
	 * 
	 * @param classNames
	 *            所需要加载的所有组件的全名数组。
	 * @throws PluginException
	 */
	public BasePluginEngine(String... classNames) throws PluginException {
		for (String className : classNames) {
			loadPlugin(className);
		}
	}

	/**
	 * 所需要加载的所有插件的类型（如：JsonPlugin.class）。
	 * 
	 * @param pluginClasses
	 *            所需要加载的所有组件的类型数组。
	 * @throws PluginException
	 */
	public BasePluginEngine(Class<? extends T>... pluginClasses)
			throws PluginException {
		for (Class<? extends T> pluginClass : pluginClasses)
			loadPlugin(pluginClass);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.atlantis.grosbeak.plugin.PluginEngine#get()
	 */
	@SuppressWarnings("unchecked")
	public T get() throws PluginException {
		for (Plugin plugin : list)
			if (plugin.canWork())
				return (T) plugin;
		throw Exceptions.makeThrow(PluginException.class, "found no plugin.");
	}

	/**
	 * 加载一个组件（组件必须实现org.atlantis.grosbeak.plugin.Plugin接口）。
	 * 
	 * @param pluginClass
	 *            需要加载组件的类型。
	 * @see org.atlantis.grosbeak.plugin.Plugin
	 * @throws PluginException
	 */
	protected void loadPlugin(Class<? extends T> pluginClass)
			throws PluginException {
		if (pluginClass != null)
			try {
				list.add((Plugin) pluginClass.newInstance());
			} catch (Exception e) {
				throw Exceptions.makeThrow(PluginException.class,
						"Plugin '%s' can not work.", pluginClass.getName());
			}
	}

	@SuppressWarnings("unchecked")
	private void loadPlugin(String pluginClassName) throws PluginException {
		try {
			if (pluginClassName != null)
				loadPlugin((Class<? extends T>) Class.forName(pluginClassName));
		} catch (ClassNotFoundException e) {
		}
	}
}
